package com.telchina.workorder.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.telchina.common.annotation.DataScope;
import com.telchina.common.core.domain.AjaxResult;
import com.telchina.common.core.domain.entity.SysOrg;
import com.telchina.common.core.domain.entity.SysUser;
import com.telchina.common.enums.ConsStatusEnum;
import com.telchina.common.enums.ReplyTypeEnum;
import com.telchina.common.enums.WorkOrderStatusEnum;
import com.telchina.common.service.IBaseFlowService;
import com.telchina.common.utils.DateUtils;
import com.telchina.common.utils.PageUtils;
import com.telchina.common.utils.SecurityUtils;
import com.telchina.common.utils.StringUtils;
import com.telchina.getui.dto.PushMessageDTO;
import com.telchina.getui.enums.MsgTemplateEnum;
import com.telchina.getui.service.CidUidRelationService;
import com.telchina.getui.util.PushUtil;
import com.telchina.workorder.domain.WoReply;
import com.telchina.workorder.domain.WoReturnVisit;
import com.telchina.workorder.domain.WoWorkOrder;
import com.telchina.workorder.domain.vo.WoWorkOrderReqVO;
import com.telchina.workorder.domain.vo.WoWorkOrderVO;
import com.telchina.workorder.mapper.WoWorkOrderMapper;
import com.telchina.workorder.service.IWoReplyService;
import com.telchina.workorder.service.IWoReturnVisitService;
import com.telchina.workorder.service.IWoWorkOrderService;
import com.telchina.workorder.third.config.BpmConfig;
import com.telchina.workorder.third.service.BpmProcessInstanceThirdService;
import com.telchina.workorder.third.service.BpmTaskThirdService;
import com.telchina.workorder.third.service.SystemThirdService;
import com.telchina.workorder.third.vo.TaskTodoItemRespVO;
import lombok.Synchronized;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 工单信息（受理单）Service业务层处理
 *
 * @author konghao
 * @date 2023-02-21
 */
@Service
@Log4j2
public class WoWorkOrderServiceImpl implements IWoWorkOrderService {

    public static final String BUSINESS_KEY = "workOrder";
    public static final String CANDIDATE_USER = "candidateUser";

    @Autowired
    private WoWorkOrderMapper woWorkOrderMapper;
    @Autowired
    private BpmProcessInstanceThirdService processInstanceThirdService;
    @Autowired
    private BpmTaskThirdService taskThirdService;
    @Autowired
    private SystemThirdService systemThirdService;
    @Autowired
    private BpmConfig bpmConfig;
    @Autowired
    private IBaseFlowService baseFlowService;
    @Autowired
    private IWoReturnVisitService returnVisitService;
    @Autowired
    private IWoReplyService replyService;
    @Resource
    private CidUidRelationService cidUidRelationService;
    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;


    /**
     * 查询工单信息（受理单）
     *
     * @param id 工单信息（受理单）ID
     * @return 工单信息（受理单）
     */
    @Override
    public WoWorkOrder selectById(String id) {
        return woWorkOrderMapper.selectById(id);
    }

    /**
     * 分页查询工单信息（受理单）列表
     *
     * @param woWorkOrder 工单信息（受理单）
     * @return 工单信息（受理单）
     */
    @Override
    public IPage<WoWorkOrder> selectList(IPage<WoWorkOrder> page, WoWorkOrder woWorkOrder) {
        return woWorkOrderMapper.selectWoWorkOrderPage(page, woWorkOrder);
    }


    /**
     * 查询所有工单信息（受理单）列表
     *
     * @param woWorkOrder 工单信息（受理单）
     * @return 工单信息（受理单）
     */
    @Override
    @DataScope(deptColumnAlias = "responsible_unit", useColumnAlias = "registrant")
    public List<WoWorkOrderVO> selectListAll(WoWorkOrderReqVO woWorkOrder) {
        // 处理模糊查询  并且兼容sql
        if (StrUtil.isNotEmpty(woWorkOrder.getOccAddress())) {
            woWorkOrder.setOccAddress("%" + woWorkOrder.getOccAddress() + "%");
        }
        if (StrUtil.isNotEmpty(woWorkOrder.getProblemDesc())) {
            woWorkOrder.setProblemDesc("%" + woWorkOrder.getProblemDesc() + "%");
        }
        if (StrUtil.isNotEmpty(woWorkOrder.getWorkOrderNumber())) {
            woWorkOrder.setWorkOrderNumber("%" + woWorkOrder.getWorkOrderNumber() + "%");
        }
        if (StrUtil.isNotEmpty(woWorkOrder.getContactsInfo())) {
            woWorkOrder.setContactsInfo("%" + woWorkOrder.getContactsInfo() + "%");
        }
        if (StrUtil.isNotEmpty(woWorkOrder.getContacts())) {
            woWorkOrder.setContacts("%" + woWorkOrder.getContacts() + "%");
        }
        if (StrUtil.isNotEmpty(woWorkOrder.getCallerNumber())) {
            woWorkOrder.setCallerNumber("%" + woWorkOrder.getCallerNumber() + "%");
        }
        PageUtils.startPage();
        return woWorkOrderMapper.selectWoWorkOrderList(woWorkOrder, null, null, null);
    }

    /**
     * 未处结
     *
     * @param woWorkOrder
     * @return
     */
    @Override
    @DataScope(deptColumnAlias = "responsible_unit", useColumnAlias = "registrant")
    public List<WoWorkOrder> selectListAllNoEnd(WoWorkOrderReqVO woWorkOrder) {
        // 处理模糊查询  并且兼容sql
        if (StrUtil.isNotEmpty(woWorkOrder.getOccAddress())) {
            woWorkOrder.setOccAddress("%" + woWorkOrder.getOccAddress() + "%");
        }
        if (StrUtil.isNotEmpty(woWorkOrder.getWorkOrderNumber())) {
            woWorkOrder.setWorkOrderNumber("%" + woWorkOrder.getWorkOrderNumber() + "%");
        }
        // 处工单单号用逗号拼接的问题
        if (StrUtil.isNotEmpty(woWorkOrder.getWorkOrderNumber())) {
            if (Arrays.asList(woWorkOrder.getWorkOrderNumber().split(",")).size() > 1) {
                woWorkOrder.setWorkOrderNumberList(Arrays.asList(woWorkOrder.getWorkOrderNumber().split(",")));
            }
        }
        if (StrUtil.isNotEmpty(woWorkOrder.getContactsInfo())) {
            woWorkOrder.setContactsInfo("%" + woWorkOrder.getContactsInfo() + "%");
        }
        if (StrUtil.isNotEmpty(woWorkOrder.getContacts())) {
            woWorkOrder.setContacts("%" + woWorkOrder.getContacts() + "%");
        }

        if (StrUtil.isNotEmpty(woWorkOrder.getProblemDesc())) {
            woWorkOrder.setProblemDesc("%" + woWorkOrder.getProblemDesc() + "%");
        }


        PageUtils.startPage();
        return woWorkOrderMapper.selectWoWorkOrderNoEnd(woWorkOrder, null);
    }

    /**
     * 并单或者解除并单
     * opt： merge 并单；Unmerge 解除并单
     *
     * @param maps
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult changeMergeWorkOrderHandle(Map<String, Object> maps) {
        // 进行数据校验
        if (ObjectUtil.isEmpty(maps.get("masterNumber")) || ObjectUtil.isEmpty(maps.get("slaveNumber"))
                || ObjectUtil.isEmpty(maps.get("opt"))) {
            return AjaxResult.error("参数输入有误！");
        }
        // 排除附单编号中错选了主单编号
        List<String> slaveNumberList = new ArrayList<>(Arrays.asList(maps.get("slaveNumber").toString().split(",")));
        slaveNumberList.remove(maps.get("masterNumber").toString());
        if (Objects.equals(maps.get("opt"), "merge")) { // 并单操作
            // ① 将主单的单据状态改为 cons_status = ConsStatusEnum.MAESTER
            woWorkOrderMapper.update(new WoWorkOrder() {{
                                         setConsStatus(ConsStatusEnum.MAESTER.getCode());
                                     }},
                    new UpdateWrapper<WoWorkOrder>()
                            .lambda().eq(WoWorkOrder::getWorkOrderNumber, maps.get("masterNumber").toString()));
            // ② 修改从单的单据状态
            woWorkOrderMapper.update(new WoWorkOrder() {{
                                         setConsStatus(ConsStatusEnum.SLAVE.getCode());
                                         setMasterOrderId(maps.get("masterNumber").toString());
                                     }},
                    new UpdateWrapper<WoWorkOrder>()
                            .lambda().in(WoWorkOrder::getWorkOrderNumber, slaveNumberList));
        } else if (Objects.equals(maps.get("opt"), "unmerge")) { // 解除并单操作
            // ① 将附单的数据重置
            woWorkOrderMapper.update(new WoWorkOrder() {{
                                         setConsStatus(ConsStatusEnum.UNMERGE.getCode());
                                         setMasterOrderId(null);
                                     }},
                    new UpdateWrapper<WoWorkOrder>()
                            .lambda().in(WoWorkOrder::getWorkOrderNumber, slaveNumberList));
            // ② 判断主单下是否还有从单
            int slaveNum = woWorkOrderMapper.selectCount(new QueryWrapper<WoWorkOrder>().lambda()
                    .eq(WoWorkOrder::getMasterOrderId, maps.get("masterNumber").toString()));
            if (slaveNum == 0) {
                // 将主单状态改为未并单
                woWorkOrderMapper.update(new WoWorkOrder() {{
                    setConsStatus(ConsStatusEnum.UNMERGE.getCode());
                }}, new QueryWrapper<WoWorkOrder>().lambda()
                        .eq(WoWorkOrder::getWorkOrderNumber, maps.get("masterNumber").toString()));
            }
        }

        return AjaxResult.success();
    }

    /**
     * 并单模块数据查询
     *
     * @param woWorkOrder
     * @return
     */
    @Override
    @DataScope(deptColumnAlias = "responsible_unit", useColumnAlias = "registrant")
    public List<WoWorkOrder> selectListMerge(WoWorkOrderReqVO woWorkOrder) {
        // 处理模糊查询  并且兼容sql
        if (StrUtil.isNotEmpty(woWorkOrder.getOccAddress())) {
            woWorkOrder.setOccAddress("%" + woWorkOrder.getOccAddress() + "%");
        }
        // 处工单单号用逗号拼接的问题
        if (StrUtil.isNotEmpty(woWorkOrder.getWorkOrderNumber())) {
            woWorkOrder.setWorkOrderNumberList(Arrays.asList(woWorkOrder.getWorkOrderNumber().split(",")));
        }
        PageUtils.startPage();
        List<WoWorkOrder> woWorkOrderList = woWorkOrderMapper.selectListMerge(woWorkOrder);
        List<String> masterNumbers = woWorkOrderList.stream().filter(A -> A.getConsStatus().equals(ConsStatusEnum.MAESTER.getCode()))
                .map(WoWorkOrder::getWorkOrderNumber).collect(Collectors.toList());
        //  获取所有附单数据
        List<WoWorkOrder> slaveWorkOrderList = new ArrayList<>();
        if (masterNumbers.size() > 0) {
            slaveWorkOrderList = woWorkOrderMapper.selectList(new QueryWrapper<WoWorkOrder>().lambda()
                    .in(WoWorkOrder::getMasterOrderId, masterNumbers));
        }
        // 组装返回的数据
        List<WoWorkOrder> finalSlaveWorkOrderList = slaveWorkOrderList;
        woWorkOrderList.stream().forEach(A -> {
            // 获取对应的附单数据
            if (A.getConsStatus().equals(ConsStatusEnum.MAESTER.getCode())) {
                A.setChildren(finalSlaveWorkOrderList.stream().filter(B -> B.getMasterOrderId().equals(A.getWorkOrderNumber())).
                        collect(Collectors.toList()));
            }
        });
        return woWorkOrderList;
    }

    /**
     * @param woWorkOrder
     * @return
     */
    @Override
    public AjaxResult todoWorkOrderListNum(WoWorkOrderReqVO woWorkOrder) {
        //  获取工单待办
        Map<String, Object> params = new HashMap<>();
        // 当前登录人
        params.put("userId", SecurityUtils.getUserId());
        // 业务实例key
        params.put("businessKey", BUSINESS_KEY);
        // 处理的范围
        params.put("assignment", "all");

        HashMap<String, Integer> result = new HashMap<>();

        AjaxResult ajaxResult = taskThirdService.getTodoTask(params);
        // 绑定业务数据 end
        if (!Objects.equals(ajaxResult.get(AjaxResult.CODE_TAG), 0)) {
            throw new RuntimeException("系统异常,未查询到代办信息" + ajaxResult.get(AjaxResult.MSG_TAG));
        }
        // 数据转换
        List<TaskTodoItemRespVO> taskTodoItemRespVOList = JSON.parseArray(ajaxResult.get(AjaxResult.DATA_TAG)
                .toString(), TaskTodoItemRespVO.class);
        // 获取流程实例的id
        List<String> instanceIds = taskTodoItemRespVOList.stream()
                .map(TaskTodoItemRespVO::getProcessInstance).map(TaskTodoItemRespVO.ProcessInstance::getId)
                .collect(Collectors.toList());
        if (instanceIds.size() == 0) {
            // 为空时返回空集合
            result.put("total", 0);
            result.put("chaoqi", 0);
            result.put("linqi", 0);
            return AjaxResult.success(result);
        }
        List<WoWorkOrderVO> woWorkOrders = woWorkOrderMapper.selectWoWorkOrderList(woWorkOrder, instanceIds,
                WorkOrderStatusEnum.MOREDISPATCH.getCode(), systemThirdService.getLoginUseDeptId());
        result.put("total", woWorkOrders.size());
        Long chaoqi = woWorkOrders.stream().filter(A->A.getExpirationTime().getTime() < new Date().getTime()).count();
        result.put("chaoqi", chaoqi.intValue());
        // 临期时间节点计算方式 dispatch_time + （processing_period * 80%）
        Long linqi = woWorkOrders.stream().filter(A->A.getExpirationTime().getTime() > new Date().getTime()
                && A.getExpirationTime().getTime() > DateUtil.offsetMinute(A.getDispatchTime(),
                (int)(A.getProcessingPeriod() * 60 * 0.8)).getTime()).count();
        result.put("linqi", linqi.intValue());
        return AjaxResult.success(result);
    }

    /**
     * 获取工单代办列表
     *
     * @param woWorkOrder
     * @return
     */
    @Override
    public List<WoWorkOrderVO> selectTodoList(WoWorkOrderReqVO woWorkOrder) {
        //  获取工单待办
        Map<String, Object> params = new HashMap<>();
        // 当前登录人
        params.put("userId", SecurityUtils.getUserId());
        // 业务实例key
        params.put("businessKey", BUSINESS_KEY);
        // 处理的范围
        params.put("assignment", "all");

        AjaxResult ajaxResult = taskThirdService.getTodoTask(params);
        // 绑定业务数据 end
        if (!Objects.equals(ajaxResult.get(AjaxResult.CODE_TAG), 0)) {
            throw new RuntimeException("系统异常,未查询到代办信息" + ajaxResult.get(AjaxResult.MSG_TAG));
        }
        // 数据转换
        List<TaskTodoItemRespVO> taskTodoItemRespVOList = JSON.parseArray(ajaxResult.get(AjaxResult.DATA_TAG)
                .toString(), TaskTodoItemRespVO.class);
        // 获取流程实例的id
        List<String> instanceIds = taskTodoItemRespVOList.stream()
                .map(TaskTodoItemRespVO::getProcessInstance).map(TaskTodoItemRespVO.ProcessInstance::getId)
                .collect(Collectors.toList());
        if (instanceIds.size() == 0) {
            // 为空时返回空集合
            return new ArrayList<WoWorkOrderVO>();
        }
        // 分页查询代办数据包含状态为多单位派单 + 责任单位和登录人为统一单位的数据
        String deptId = systemThirdService.getLoginUseDeptId();
        PageUtils.startPage();
        List<WoWorkOrderVO> woWorkOrders = woWorkOrderMapper.selectWoWorkOrderList(woWorkOrder, instanceIds,
                WorkOrderStatusEnum.MOREDISPATCH.getCode(), deptId);
        woWorkOrders.stream().forEach(A -> {
            // 获取工作流任务数据
            if (StringUtils.isNotEmpty(A.getInstanceId()) && !A.getWorkOrderStatus().equals(WorkOrderStatusEnum.MOREDISPATCH.getCode())) {
                A.setTaskTodoItemRespVO(taskTodoItemRespVOList.stream()
                        .filter(B -> B.getProcessInstance().getId().equals(A.getInstanceId())).collect(Collectors.toList()).get(0));
            }
            // 剩余到期时间
            if (A.getDispatchTime() != null) {
                A.setSurplusTime(A.getExpirationTime().getTime() - new Date().getTime());
            }
        });
        return woWorkOrders;
    }

    /**
     * 获得指定流程实例的任务列表
     *
     * @param processInstanceId
     * @return
     */
    @Override
    public List<Map> getTaskListByProcessInstanceId(String processInstanceId) {
        AjaxResult ajaxResult = taskThirdService.getTaskListByProcessInstanceId(processInstanceId);
        // 绑定业务数据 end
        if (!Objects.equals(ajaxResult.get(AjaxResult.CODE_TAG), 0)) {
            throw new RuntimeException("系统异常,未查询到代办信息" + ajaxResult.get(AjaxResult.MSG_TAG));
        }
        List<Map> processInstanceList = JSON.parseArray(ajaxResult.get(AjaxResult.DATA_TAG).toString(), Map.class);
        // 获取涉及的用户信息
        List<String> userIds = processInstanceList.stream().filter(A -> !Objects.isNull(A.get("todoUserId")))
                .map(A -> A.get("todoUserId").toString()).collect(Collectors.toList());
        // 获取涉及的部门信息
        List<String> deptIds = processInstanceList.stream().filter(A -> !Objects.isNull(A.get("todoDeptId")))
                .map(A -> A.get("todoDeptId").toString()).collect(Collectors.toList());
        // 待处理的数据回显
        processInstanceList.stream().forEach(A -> {
            if (A.get("result") != null && "1".equals(A.get("result").toString())) {
                if (!Objects.isNull(A.get("candidateUserId"))) {
                    List<SysUser> candidateUsers = systemThirdService.getSysUserInfoList(Arrays.asList(A.get("candidateUserId").toString().split(",")));
                    A.put("candidateUserNames", candidateUsers.stream().map(p -> p.getUserName() + "(" + p.getLoginName() + ")").collect(Collectors.joining(",")));
                }
            }
        });
        // 已经处理的数据回显
        if (userIds.size() != 0 && deptIds.size() != 0) {
            List<SysUser> sysUsers = systemThirdService.getSysUserInfoList(userIds);
            List<SysOrg> sysOrgs = systemThirdService.getDeptIdInfoList(deptIds);
            // 处理数据
            processInstanceList.stream().forEach(A -> {

                if (!Objects.isNull(A.get("todoUserId")))
                    A.put("userName", sysUsers.stream()
                            .filter(B -> B.getId().equals(String.valueOf(A.get("todoUserId")))).collect(Collectors.toList())
                            .get(0).getUserName());


                if (!Objects.isNull(A.get("todoDeptId")))
                    A.put("deptName", sysOrgs.stream()
                            .filter(B -> B.getId().equals(String.valueOf(A.get("todoDeptId")))).collect(Collectors.toList())
                            .get(0).getName());
            });
        }


        // 手动添加 流程启动前的流转记录  包含生成工单  派单  多单位派单
        // 获取工单信息
        WoWorkOrder woWorkOrder = woWorkOrderMapper.selectOne(new QueryWrapper<WoWorkOrder>().lambda().eq(WoWorkOrder::getInstanceId, processInstanceId));
        if (woWorkOrder != null) {
            // 用户
            String userName = systemThirdService.getSysUserInfo(woWorkOrder.getRegistrant()).getUserName();
            // 部门
            String deptName = systemThirdService.getLoginUseDeptByUserId(woWorkOrder.getRegistrant()).getName();
            processInstanceList.add(new HashMap() {{
                put("operate", "2".equals(woWorkOrder.getParentChild()) ? WorkOrderStatusEnum.MOREDISPATCH.getInfo()
                        : WorkOrderStatusEnum.DISPATCH.getInfo());
                put("userName", userName);
                put("endTime", woWorkOrder.getDispatchTime().getTime());
                put("createTime", woWorkOrder.getCreateTime().getTime());
                put("deptName", deptName);
                put("name", WorkOrderStatusEnum.DISPATCH.getInfo());
            }});
            processInstanceList.add(new HashMap() {{
                put("operate", WorkOrderStatusEnum.DRAFT.getInfo());
                put("userName", userName);
                put("endTime", woWorkOrder.getCreateTime().getTime());
                put("deptName", deptName);
                put("name", WorkOrderStatusEnum.DRAFT.getInfo());
            }});
        }
        // 数据转换
        return processInstanceList;
    }


    /**
     * 新增工单信息（受理单） 并返回id
     *
     * @param woWorkOrder 工单信息（受理单）
     * @return 结果
     */
    @Override
    public AjaxResult insert(WoWorkOrder woWorkOrder) {
        // 处理工单单号的问题
        woWorkOrder.setWorkOrderNumber(getWorkOrderNumber());
        // 并单状态(0:未并单 ; 1:附单; 2:主单)
        woWorkOrder.setConsStatus("0");
        // 母子单状态(0:非母子 ; 1:子单；2:母单)
        woWorkOrder.setParentChild("0");
        woWorkOrder.setCreateTime(DateUtils.getNowDate());
        return woWorkOrderMapper.insert(woWorkOrder) > 0 ? AjaxResult.success("", woWorkOrder) : AjaxResult.error();
    }

    /**
     * 修改工单信息（受理单）
     *
     * @param woWorkOrder 工单信息（受理单）
     * @return 结果
     */
    @Override
    public AjaxResult update(WoWorkOrder woWorkOrder) {
        woWorkOrder.setUpdateTime(DateUtils.getNowDate());
        return woWorkOrderMapper.updateById(woWorkOrder) > 0 ? AjaxResult.success(woWorkOrder) : AjaxResult.error();
    }

    /**
     * 批量删除工单信息（受理单）
     *
     * @param ids 需要删除的工单信息（受理单）ID
     * @return 结果
     */
    @Override
    public int deleteByIds(String[] ids) {
        return woWorkOrderMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除工单信息（受理单）信息
     *
     * @param id 工单信息（受理单）ID
     * @return 结果
     */
    @Override
    public int deleteById(String id) {
        return woWorkOrderMapper.deleteById(id);
    }

    /**
     * 派单业务处理
     *
     * @param maps 派单数据参数
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult dispatchWorkOrder(Map<String, Object> maps) {
        // 进行数据校验
        if (Objects.isNull(maps.get("workOrderNumber"))) {
            return AjaxResult.error("参数输入有误！");
        }
        // 主单单号
        String workOrderNumber = String.valueOf(maps.get("workOrderNumber"));
        // 进行流程处理的单据信息
        List<WoWorkOrder> workOrders = new ArrayList<>();
        // 获取工单信息 （主单） -> 草稿（新单据）
        WoWorkOrder woWorkOrder = woWorkOrderMapper.selectOne(new QueryWrapper<WoWorkOrder>().lambda()
                .eq(WoWorkOrder::getWorkOrderNumber, workOrderNumber)
                .and(A -> A.eq(WoWorkOrder::getWorkOrderStatus, WorkOrderStatusEnum.DRAFT.getCode())
                        .or().eq(WoWorkOrder::getWorkOrderStatus, WorkOrderStatusEnum.MOREDISPATCH.getCode())
                        .or().eq(WoWorkOrder::getWorkOrderStatus, WorkOrderStatusEnum.REPLY_RECEIPT.getCode())
                        .or().eq(WoWorkOrder::getWorkOrderStatus, WorkOrderStatusEnum.REPLY_CHARGEBACK.getCode())));
        if (Objects.isNull(woWorkOrder)) {
            return AjaxResult.error("未找到新单据：【" + workOrderNumber + "】");
        }
        List<String> deptIds = new ArrayList<String>();
        // 获取责任单位
        if (!Objects.isNull(maps.get("depts"))) {
            deptIds = (ArrayList<String>) maps.get("depts");
        }
        // 责任单位为0时  即为直接派单   大于0时为多单位派单
        if (deptIds.size() > 0) {
            Long period = Objects.isNull(maps.get("timeOut")) ? woWorkOrder.getProcessingPeriod()
                    : Long.valueOf(String.valueOf(maps.get("timeOut")));
            // 此时进行工单复制 并启动审批流程
            workOrders = copyWorkOrder(woWorkOrder, deptIds, period);
            // 复制数据完成后处理主单状态
            woWorkOrder.setParentChild("2");
            // 多单位派单时  工单状态改为 ‘多单位派单’ 并且不启动流程
            woWorkOrder.setWorkOrderStatus(WorkOrderStatusEnum.MOREDISPATCH.getCode());
        } else {
            // 非母子单
            woWorkOrder.setParentChild("0");
            workOrders.add(woWorkOrder);// 将主单也放到处理集合中 为了启动流程
        }
        // 派单时间
        woWorkOrder.setDispatchTime(new Date());
        // 到期时间
        woWorkOrder.setExpirationTime(DateUtils.addHours(new Date(), woWorkOrder.getProcessingPeriod().intValue()));
        // 保存主单信息
        woWorkOrderMapper.updateById(woWorkOrder);
        // 数据修改和保存完毕后进行流程启动 (耗时考虑多线程处理)
        workOrders.stream().forEach(A -> {
            // TODO 发送流程启动命令并指定处理单位 todo_user  返回instanceId 标志流程启动成功
            String instanceId = startFlow(A);
            A.setInstanceId(instanceId);
            // 派单
            A.setWorkOrderStatus(WorkOrderStatusEnum.DISPATCH.getCode());
            woWorkOrderMapper.updateById(A);
        });
        return AjaxResult.success("派单成功");
    }

    /**
     * 工单业务处理流转
     *
     * @param maps
     * @return
     */
    @Override
    public AjaxResult sendLastWorkOrder(Map<String, Object> maps) {
        // 进行数据校验
        if (Objects.isNull(maps.get("workOrderNumber"))) {
            return AjaxResult.error("参数输入有误！");
        }
        // 进行数据校验
        if (Objects.isNull(maps.get("taskId"))) {
            return AjaxResult.error("任务id为空！");
        }
        // 进行数据校验
        if (Objects.isNull(maps.get("workOrderStatus"))) {
            return AjaxResult.error("工单流转类型为空！");
        }
        // 主单单号
        String workOrderNumber = String.valueOf(maps.get("workOrderNumber"));
        // 进行流程处理的单据信息
        List<WoWorkOrder> workOrders = new ArrayList<>();
        // 获取工单信息 （主单） -> 进行异常判定
        WoWorkOrder woWorkOrder = getWoWorkOrder(workOrderNumber,
                WorkOrderStatusEnum.getValueOf(maps.get("workOrderStatus").toString()));
        if (Objects.isNull(woWorkOrder)) {
            return AjaxResult.error("未找到派单单据：【" + workOrderNumber + "】");
        }
        // 如果为多单位派单的主单 不需要流程处理  直接结单
        if ("nostart".equals(maps.get("taskId"))) {
            updateWorkOrderInfo(maps, woWorkOrder);
            return AjaxResult.success("操作成功");
        }
        // 验证任务
        baseFlowService.checkUserIdDoTask(maps.get("taskId").toString());
        String deptId = "";
        // 获取责任单位
        if (Objects.isNull(maps.get("dept"))) {
            return AjaxResult.error("派单单位为空，派单失败");
        }
        deptId = String.valueOf(maps.get("dept"));
        // 获取部门下所有用户
        List<SysUser> midUserOrgs = systemThirdService.getSysUserByDeptId(deptId);
        if (midUserOrgs.size() == 0) {
            return AjaxResult.error("派单单位无人员信息，不可派单");
        }
        // 修改流程处理人参数
        List<String> receiveUserIds = midUserOrgs.stream().map(SysUser::getId).collect(Collectors.toList());
        maps.put("variables", new HashMap<String, Object>() {{
            put(CANDIDATE_USER, String.join(",", receiveUserIds));
        }}); // 下一步处理人
        maps.put("id", maps.get("taskId"));
        AjaxResult updateTaskResult = taskThirdService.updateTaskVariable(maps);
        if (!Objects.equals(updateTaskResult.get(AjaxResult.CODE_TAG), 0)) {
            throw new RuntimeException("系统异常,参数设置失败：" + updateTaskResult.get(AjaxResult.MSG_TAG));
        }
        // 任务办理  开始
        // 组装参数
        Map<String, Object> approveTaskParam = new HashMap<>();
        approveTaskParam.put("userId", SecurityUtils.getUserId());
        approveTaskParam.put("deptId", systemThirdService.getLoginUseDeptId());
        approveTaskParam.put("operate", WorkOrderStatusEnum.getValueOf(maps.get("workOrderStatus").toString()).getInfo());
        approveTaskParam.put("id", maps.get("taskId"));
        // b绑定的流程参数  按钮设置的时候绑定
        approveTaskParam.put("variables", JSONObject.parseObject((String) maps.get("buttonData"), HashMap.class));
        AjaxResult approveTaskResult = taskThirdService.approveTask(approveTaskParam);
        if (!Objects.equals(approveTaskResult.get(AjaxResult.CODE_TAG), 0)) {
            throw new RuntimeException("系统异常，任务转交失败" + approveTaskResult.get(AjaxResult.MSG_TAG));
        }
        updateWorkOrderInfo(maps, woWorkOrder);
        pushTodoMessage(receiveUserIds, woWorkOrder);
        return AjaxResult.success("操作成功");
    }

    /**
     * 流程审批过程中修改工单数据
     *
     * @param maps
     * @param woWorkOrder
     */
    private void updateWorkOrderInfo(Map<String, Object> maps, WoWorkOrder woWorkOrder) {


        // 工单改派 OR 再派单
        // 如果为工单改派的时候 将责任单位一起修改了
        if (maps.get("workOrderStatus").toString().equals(WorkOrderStatusEnum.REASSIGNMENT.getCode()) ||
                maps.get("workOrderStatus").toString().equals(WorkOrderStatusEnum.AGAINSEND.getCode())) {
            woWorkOrder.setResponsibleUnit(maps.get("dept").toString());
            // 工单流程：派单、工单改派、再派单时，置为当前时间 + 重置到期时间；
            woWorkOrder.setDispatchTime(new Date());
            // 重置到期时间；
            woWorkOrder.setExpirationTime(DateUtils.addHours(new Date(), woWorkOrder.getProcessingPeriod().intValue()));
            // 派单或再派单或改派时将值清空
            woWorkOrder.setFeedbackTime(null);
            // 反馈方式
            woWorkOrder.setFeedbackMode(null);
        }
        // 完结
        // 如果工单状态为审批完成  处理一些列完成后的任务
        if (maps.get("workOrderStatus").toString().equals(WorkOrderStatusEnum.FINISH.getCode())) {
            woWorkOrder.setCompletionTime(new Date());
            // 工单结案时，将最后一条回访单的满意度写入此字段
            WoReturnVisit returnVisit = returnVisitService.selectNewOneByWorkOrderNumber(woWorkOrder.getWorkOrderNumber());
            if (returnVisit != null) {
                //  写入
                woWorkOrder.setProcessOpinion(returnVisit.getProcessOpinion());
                woWorkOrder.setResultOpinion(returnVisit.getResultOpinion());
            }
            // 是否包含附单
//            if (ConsStatusEnum.MAESTER.equals(woWorkOrder.getConsStatus())) {
//
//            }
        }
        // 工单回单 OR 工单回退
        if (maps.get("workOrderStatus").toString().equals(WorkOrderStatusEnum.REPLY_RECEIPT.getCode()) ||
                maps.get("workOrderStatus").toString().equals(WorkOrderStatusEnum.REPLY_CHARGEBACK.getCode())) {
            // 工单流程：工单回复时，将字段置为回复；工单回退时，将字段置为回退
            // 判断只有责任单位到话务员这一步需要填写反馈时间和反馈方式
            if (woWorkOrder.getWorkOrderStatus().equals(WorkOrderStatusEnum.RECEIVE.getCode()) && woWorkOrder.getWorkOrderStatus()
                    .equals(WorkOrderStatusEnum.REASSIGNMENTLAST_CHARGEBACK.getCode()) && woWorkOrder.getWorkOrderStatus()
                    .equals(WorkOrderStatusEnum.REASSIGNMENTLAST_RECEIPT.getCode())) {
                woWorkOrder.setFeedbackMode(maps.get("workOrderStatus").toString().equals(WorkOrderStatusEnum.REPLY_RECEIPT.
                        getCode()) ? ReplyTypeEnum.REPLY_RECEIPT.getCode() : ReplyTypeEnum.REPLY_CHARGEBACK.getCode());
                // 工单回复或回退时值置为当前时间；
                woWorkOrder.setFeedbackTime(new Date());
                // 工单流程：工单回复时，判断该单位是否以前回退过该工单，如果回退过，记为推诿工单。
                // ① 获取登录人坐在单位
                String deptId = systemThirdService.getLoginUseDeptId();
                List<WoReply> woReplyList = replyService.selectListAll(new WoReply() {{
                    setDeptId(deptId);
                    setReplyType(ReplyTypeEnum.REPLY_CHARGEBACK.getCode());
                    setWorkOrderNumber(woWorkOrder.getWorkOrderNumber());
                }});
                if (woReplyList.size() > 0) {
                    woWorkOrder.setEntrustOrder("0");
                }
            }
        }
        // 任务转交成功
        woWorkOrder.setWorkOrderStatus(maps.get("workOrderStatus").toString());
        woWorkOrderMapper.updateById(woWorkOrder);
    }

    /**
     * 推送待办通知
     *
     * @param userIds
     * @param woWorkOrder
     */
    private void pushTodoMessage(List<String> userIds, WoWorkOrder woWorkOrder) {
        try {
            // 异步执行
            threadPoolTaskExecutor.execute(() -> {
                // 校验
                if (Objects.isNull(userIds) || userIds.isEmpty()) return;
                // 根据用户ID获取cid
                List<String> cids = cidUidRelationService.getCidByUid(userIds);
                // 校验
                if (Objects.isNull(cids) || cids.isEmpty()) return;
                String workOrderNumber = woWorkOrder.getWorkOrderNumber();
                String workOrderId = woWorkOrder.getId();
                final MsgTemplateEnum woTodoMsg = MsgTemplateEnum.WO_TODO_MSG;
                String title = woTodoMsg.title;
                String content = String.format(woTodoMsg.content, workOrderNumber);
                // 构建消息体
                PushMessageDTO pushMessageDTO = new PushMessageDTO();
                pushMessageDTO.setTitle(title);
                pushMessageDTO.setBody(content);
                pushMessageDTO.setCids(cids);
                pushMessageDTO.setExt(JSON.toJSONString(new HashMap<String, Object>() {{
                    put("workOrderNumber", workOrderNumber);
                    put("workOrderId", workOrderId);
                    put("msgType", woTodoMsg.type);
                }}));
                // 发送推送
                PushUtil.pushBatchByCid(pushMessageDTO);
            });
        } catch (Exception e) {
            log.error("推送待办通知失败", e);
        }
    }

    /**
     * @param workOrderNumber
     * @return
     */
    @Override
    public WoWorkOrderVO getWorkOrderByWorkOrderNumber(String workOrderNumber) {
        WoWorkOrder workOrder = woWorkOrderMapper.selectOne(new QueryWrapper<WoWorkOrder>().lambda()
                .eq(WoWorkOrder::getWorkOrderNumber, workOrderNumber));
        WoWorkOrderVO woWorkOrderVO = new WoWorkOrderVO();
        BeanUtils.copyProperties(workOrder, woWorkOrderVO);
        // 母单
        if ("2".equals(woWorkOrderVO.getParentChild())) {
            List<WoWorkOrder> woWorkOrders = woWorkOrderMapper.selectList(new QueryWrapper<WoWorkOrder>().lambda()
                    .select(WoWorkOrder::getWorkOrderNumber)
                    .eq(WoWorkOrder::getParentOrderId, woWorkOrderVO.getWorkOrderNumber()));
            woWorkOrderVO.setChildWorkOrderNumbers(woWorkOrders.stream().map(WoWorkOrder::getWorkOrderNumber).collect(Collectors.joining(",")));
        }
        return woWorkOrderVO;
    }

    /**
     * 通过单号修改
     *
     * @param woWorkOrder
     */
    @Override
    public int updateByWorkOrderNumber(WoWorkOrder woWorkOrder) {
        return woWorkOrderMapper.update(woWorkOrder, new QueryWrapper<WoWorkOrder>().lambda()
                .eq(WoWorkOrder::getWorkOrderNumber, woWorkOrder.getWorkOrderNumber()));
    }


    /**
     * \
     * 常规判断  状态和操作是否相符
     *
     * @param workOrderNumber
     * @param worderOrderStatusEnum
     * @return
     */
    private WoWorkOrder getWoWorkOrder(String workOrderNumber, WorkOrderStatusEnum worderOrderStatusEnum) {
        WoWorkOrder woWorkOrder = woWorkOrderMapper.selectOne(new QueryWrapper<WoWorkOrder>().lambda()
                .eq(WoWorkOrder::getWorkOrderNumber, workOrderNumber));
        switch (worderOrderStatusEnum) {
            case DISPATCH:
                woWorkOrder = woWorkOrder.getWorkOrderStatus().equals(WorkOrderStatusEnum.DRAFT.getCode()) ? woWorkOrder : null;
                break;
            case REASSIGNMENLAST:
                woWorkOrder = woWorkOrder.getWorkOrderStatus().equals(WorkOrderStatusEnum.RECEIVE.getCode()) || woWorkOrder.getWorkOrderStatus().equals(WorkOrderStatusEnum.AGAINSEND.getCode())
                        ? woWorkOrder : null;
                break;
            case REASSIGNMENTLAST_RECEIPT:
            case REASSIGNMENTLAST_CHARGEBACK:
                woWorkOrder = woWorkOrder.getWorkOrderStatus().equals(WorkOrderStatusEnum.REASSIGNMENLAST.getCode()) ? woWorkOrder : null;
                break;
            case REPLY_RECEIPT:
            case REPLY_CHARGEBACK:
                woWorkOrder = (woWorkOrder.getWorkOrderStatus().equals(WorkOrderStatusEnum.REASSIGNMENTLAST_RECEIPT.getCode())
                        || woWorkOrder.getWorkOrderStatus().equals(WorkOrderStatusEnum.RECEIVE.getCode())
                        || woWorkOrder.getWorkOrderStatus().equals(WorkOrderStatusEnum.REASSIGNMENTLAST_CHARGEBACK.getCode())
                        || woWorkOrder.getWorkOrderStatus().equals(WorkOrderStatusEnum.AGAINSEND.getCode())
                        || woWorkOrder.getWorkOrderStatus().equals(WorkOrderStatusEnum.MOREDISPATCH.getCode())
                        || woWorkOrder.getWorkOrderStatus().equals(WorkOrderStatusEnum.REASSIGNMENT.getCode())) ? woWorkOrder : null;
                break;
            case FINISH:
            case REASSIGNMENT:
            case AGAINSEND:
                woWorkOrder = (woWorkOrder.getWorkOrderStatus().equals(WorkOrderStatusEnum.REPLY_RECEIPT.getCode())
                        || woWorkOrder.getWorkOrderStatus().equals(WorkOrderStatusEnum.MOREDISPATCH.getCode())
                        || woWorkOrder.getWorkOrderStatus().equals(WorkOrderStatusEnum.REPLY_CHARGEBACK.getCode())) ? woWorkOrder : null;
                break;
        }
        return woWorkOrder;
    }


    /**
     * 启动工单流程
     *
     * @param woWorkOrder
     * @return
     */
    private String startFlow(WoWorkOrder woWorkOrder) {
        Map<String, Object> params = new HashMap<>();
        // 当前登录人
        params.put("userId", SecurityUtils.getUserId());
        // 流程实例key
        params.put("processDefinitionKey", bpmConfig.getWorkOrderProcessDefinitionKey());
        // 业务实例key
        params.put("businessKey", BUSINESS_KEY);
        // 绑定业务数据 start
        Map<String, Object> variablesParams = new HashMap<>();
        // 获取责任部门下所有的用户
        List<SysUser> midUserOrgs = systemThirdService.getSysUserByDeptId(woWorkOrder.getResponsibleUnit());
        if (midUserOrgs.size() == 0) {
            throw new RuntimeException("派单单位无人员信息，不可派单");
        }
        List<String> userIdList = midUserOrgs.stream().map(SysUser::getId).collect(Collectors.toList());
        String userIds = String.join(",", userIdList);
        if (StringUtils.isEmpty(userIds)) {
            throw new RuntimeException("责任部门下无可审批的人员，提交流程异常");
        }
        variablesParams.put(CANDIDATE_USER, userIds);
        params.put("variables", variablesParams);
        // 绑定业务数据 end
        AjaxResult ajaxResult = processInstanceThirdService.createProcessInstance(params);
        if (!Objects.equals(ajaxResult.get(AjaxResult.CODE_TAG), 0)) {
            throw new RuntimeException("启动失败，提交流程异常" + ajaxResult.get(AjaxResult.MSG_TAG));
        }
        pushTodoMessage(userIdList, woWorkOrder);
        return String.valueOf(ajaxResult.get(AjaxResult.DATA_TAG));
    }

    /**
     * 并启动审批流程
     *
     * @param woWorkOrder 主单
     * @param deptIds     派单责任单位
     * @
     */
    private List<WoWorkOrder> copyWorkOrder(WoWorkOrder woWorkOrder, List<String> deptIds, Long period) {
        List<WoWorkOrder> childOrderIds = new ArrayList<>();
        // 循环处理部门单据
        for (String deptId : deptIds) {
            WoWorkOrder woWorkOrderChild = new WoWorkOrder();
            BeanUtils.copyProperties(woWorkOrder, woWorkOrderChild);
            woWorkOrderChild.setId(null);// 重置id
            woWorkOrderChild.setWorkOrderNumber(getWorkOrderNumber());
            // 母子单状态(0:非母子 ; 1:子单；2:母单)
            woWorkOrderChild.setParentChild("1");
            woWorkOrderChild.setParentOrderId(woWorkOrder.getWorkOrderNumber());
            // 草稿
            woWorkOrderChild.setWorkOrderStatus(WorkOrderStatusEnum.DRAFT.getCode());
            // 责任单位
            woWorkOrderChild.setResponsibleUnit(deptId);
            // 处理期限
            woWorkOrderChild.setProcessingPeriod(period);

            // 派单时间
            woWorkOrderChild.setDispatchTime(new Date());
            // 到期时间
            woWorkOrderChild.setExpirationTime(DateUtils.addHours(new Date(), period.intValue()));
            // 保存子单信息
            woWorkOrderMapper.insert(woWorkOrderChild);

            childOrderIds.add(woWorkOrderChild);
        }
        return childOrderIds;
    }

    /**
     * 同步方法生成工单编号
     *
     * @return
     */
    @Synchronized
    private String getWorkOrderNumber() {
        String paramsDate = DateUtils.parseDateToStr("yyMMdd", DateUtils.getNowDate());
        // 获取当日最大单号
        WoWorkOrder woWorkOrder = woWorkOrderMapper.selectOne(new QueryWrapper<WoWorkOrder>().select("max(work_order_number) work_order_number")
                .likeRight("work_order_number", paramsDate));
        if (woWorkOrder != null) {
            return String.valueOf(new BigDecimal(woWorkOrder.getWorkOrderNumber()).add(BigDecimal.ONE));
        } else {
            return paramsDate + "00001";
        }
    }
}
